/*
	Copyright 2025 MaxwellWang Vedder	B5106D@Outlook.com

	This file is part of the MwIAP firmware.

	The MwIAP firmware is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    The MwIAP firmware is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
/******************************************************************************
 * Include files
 ******************************************************************************/
#include "main.h"
//#include "cw32l010_gpio.h"
//#include "cw32l010_flash.h"
//#include "cw32l010_systick.h"
//#include "cw32l010_sysctrl.h"
//#include "interrupts_cw32l010.h"
#include "common.h"
#include "flash_helper.h"
//#include <string.h>
/******************************************************************************
 * Local type definitions ('typedef')
 ******************************************************************************/
#define BAUD_RATE        115200
#define PCLK_FREQ        48000000
//#define AppAdress       0x00002000  //APP start adress

#define MaxScanIAPTime  0x100000   //最长扫描uart的次数
//extern func_ptr_t Jump_To_Application;

//#define EnterUartScanByte   0x100000    //启动时候扫描uart一个byte的最大时间

/**
 ******************************************************************************
 ** \brief  Main function of project
 **
 ** \return uint32_t return value, if needed
 **
 ** bootloader 放在程序最开始位置 通过判断是否执行APP 运行程序
 **
 ******************************************************************************/

int main(void){
    RCC_Configuration();    //init sysclk = 48M
    //bootloader is uart RX decode data is 5a5a enter bootloader mode
    UART1_Configuration(0);
    //UART_ITConfig(CW_UART1,UART_IT_RC,ENABLE);
    scanBootloader();   //里面有较长的扫描循环
    UART1_Configuration(1); //进入bootloader 发送ready命令并等待更新
    sendStartIAP(); //告诉主机开始升级
    __SYSCTRL_FLASH_CLK_ENABLE();
    while(1){
        ScanUpdatePack();   //扫描升级数据
    }
	//NVIC_EnableIRQ(UART1_IRQn);
    //初始化扫描UartRX 内容 收到升级指令进行升级 超时进入正常程序
}
/**
 * @brief 扫描是否进入bootloader
 * 
 * 
*/
void scanBootloader(void){
    int OverBootloaderTime = MaxScanIAPTime;    //溢出时间
    uint32_t desAppAdrr = GetAPPAddr();
    //uint32_t JumpAddress;   //跳转的flash地址
    if(desAppAdrr==0xffffffff){
        //地址里面没有数据 说明没有AP数据 会一直等到bootloader 载入有效程序 否则限定最长200ms跳到APP
        OverBootloaderTime = -1;    //无时间限制
    }
    while(1){
        if(OverBootloaderTime!=-1){
            OverBootloaderTime--;
            if(OverBootloaderTime==0){
                //达到溢出时间 跳入APP程序
                //__disable_irq();    // 关中断
                if ((desAppAdrr & 0x2FFE0000 ) == 0x20000000)  //判断跳转的地址是否有合法程序存在
                {
                    flash_helper_jump_to_APP();
                    // 向用户的APP程序进行跳转
                    //JumpAddress = *(__IO uint32_t*) (AppAdress + 4);    // ResetHandle函数的地址
                    //Jump_To_Application = (func_ptr_t) JumpAddress;    // 将地址强制转换为函数指针            
                    //__set_MSP(*(__IO uint32_t*) AppAdress);   // 设置用户APP程序的栈地址  
                    //Jump_To_Application();    // 跳入用户APP程序的ResetHandle处
                }
            }
        }
        //主程序循环扫描uartRX
        if(IsEnterBootloader()){
            //检测到进入bootloader信号 转入bootloader
            //UART1_Configuration(1); //开启双向串口 进入升级模式 此时不能断电
            return;  //跳出循环执行下一步 
        }
    }
}
/**
  * @brief  Configures the different system clocks.
  * @param  None
  * @retval None
  */
void RCC_Configuration(void)
{
    __SYSCTRL_FLASH_CLK_ENABLE();
	CW_SYSCTRL->AHBEN_f.FLASH = 1;
  	CW_FLASH->CR2 = 0x5A5A0000 | 0x00000001;
    /* 0. HSI使能并校准 */
    // 48MHz / 1
    SYSCTRL_HSI_Enable( SYSCTRL_HSIOSC_DIV1);
    SYSCTRL_SYSCLKSRC_Config(SYSCTRL_SYSCLKSRC_HSI);//配置时钟源，高速内部时钟
	SYSCTRL_HCLKPRS_Config(SYSCTRL_HCLK_DIV1);//配置SysClk 到 HCLK的分频系数
  	SYSCTRL_PCLKPRS_Config(SYSCTRL_PCLK_DIV1);//配置HCLK 到 PCLK的分频系数
}

/***
 * @brief initial uart1 PA7 PA8
 * @param  status 0:RX mode 1: TRX mode
 * @retval None
 * 
 * 
*/
void UART1_Configuration(int status)
{
    GPIO_InitTypeDef GPIO_InitStructure = {0};
    UART_InitTypeDef UART_InitStructure = {0};

    //时钟使能
    __SYSCTRL_GPIOA_CLK_ENABLE();
	//__SYSCTRL_GPIOB_CLK_ENABLE();
    __SYSCTRL_UART1_CLK_ENABLE();

    // 默认UART1.TX 映射到PA08 UART1.RX 映射到PA09，
    // 如需分配其他引脚请自行修改
    // 先设置UART TX RX 复用，后设置GPIO的属性，避免口线上出现毛刺
    //    PA05_AFx_UART1RXD();
    //    PA06_AFx_UART1TXD();
	PA07_AFx_UART1RXD();
    if(status==1)
    PA08_AFx_UART1TXD();
    //PA00_AFx_UART1RXD();
	//PA01_AFx_UART1TXD();
    if(status==1){
        GPIO_InitStructure.Pins = GPIO_PIN_8;
        GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
        GPIO_Init(CW_GPIOA, &GPIO_InitStructure);
    }

    GPIO_InitStructure.Pins = GPIO_PIN_7;
    GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
    GPIO_Init(CW_GPIOA, &GPIO_InitStructure);

    UART1_DeInit();
    UART_InitStructure.UART_BaudRate = BAUD_RATE;
    UART_InitStructure.UART_Over = UART_Over_16;
    UART_InitStructure.UART_Source = UART_Source_PCLK;
    UART_InitStructure.UART_UclkFreq = PCLK_FREQ;
    UART_InitStructure.UART_StartBit = UART_StartBit_FE;
    UART_InitStructure.UART_StopBits = UART_StopBits_1;
    UART_InitStructure.UART_Parity = UART_Parity_No;
    UART_InitStructure.UART_HardwareFlowControl = UART_HardwareFlowControl_None;
    if(status==1)
    UART_InitStructure.UART_Mode = UART_Mode_Rx | UART_Mode_Tx;
    else
    UART_InitStructure.UART_Mode = UART_Mode_Rx;

    UART_Init(CW_UART1, &UART_InitStructure);
}
/******************************************************************************
 * EOF (not truncated)
 ******************************************************************************/
#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
    /* USER CODE BEGIN 6 */
    /* User can add his own implementation to report the file name and line number,
       tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
    /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

